/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef _SPEEDCONTROLLER_H_
#define _SPEEDCONTROLLER_H_

#include <utility.h>

class SpeedController {
protected:
    int                                 _speed;

    int                                 _unit_ticks;

    int                                 _loop;

    // temporary counters
    Uint64                              _begin;

    int                                 _cnt;

public:
    SpeedController()
        : _speed(0)
        , _unit_ticks(0)
        , _loop(-1)
        , _begin(0)
        , _cnt(0)
    {
    }

    SpeedController(int speed, int unit_ticks)
        : _speed(speed)
        , _unit_ticks(unit_ticks)
        , _loop(-1)
        , _cnt(0)
    {
        _begin = get_ticks();
    }

    void set_loop(int n) { _loop = n; }

    bool stop_pred()
    {
        return (_speed <= 0 || _loop == 0
                || (_loop == 1 && _cnt >= _speed));
    }

    bool step_pred()
    {
        Uint64 now;
        int    diff;

        if (_speed <= 0 || _loop == 0)
            return false;

        now  = get_ticks();
        diff = (int) (now - _begin);
        if (diff < 0)
            diff = 0;

        // (_speed / _unit_ticks) == (_cnt / diff)
        if ((_speed * diff) >= (_unit_ticks * _cnt)) {
            if (_cnt < _speed) {
                ++_cnt;

                return true;
            }
            else {
                if (diff >= _unit_ticks) {
                    if (_loop > 0)
                        --_loop;

                    if (_loop != 0) {
                        _begin = now;
                        _cnt   = 0;
                    }
                }
            }
        }

        return false;
    }

    double get_real_speed()
    {
        Uint64 now;
        int    diff;

        if (_speed <= 0 || _loop == 0)
            return 0.0;

        now  = get_ticks();
        diff = (int) (now - _begin);
        if (diff < 0)
            diff = 0;

        if (diff == 0)
            return 0.0;

        return (double) (_cnt * _unit_ticks) / (double) diff;
    }

    void reset_speed(int speed, int unit_ticks)
    {
        _speed      = speed;
        _unit_ticks = unit_ticks;
        _begin      = get_ticks();
        _cnt        = 0;
    }

    Uint64 get_begin_ticks() { return _begin; }
};

#endif /* _SPEEDCONTROLLER_H_ */
